#include "dtu_log.h"
#include <stdarg.h>
#include <sys/stat.h>
#include <syslog.h>

/* ANSI颜色代码 */
#define ANSI_COLOR_RED     "\x1b[31m"
#define ANSI_COLOR_YELLOW  "\x1b[33m"
#define ANSI_COLOR_BLUE    "\x1b[34m"
#define ANSI_COLOR_MAGENTA "\x1b[35m"
#define ANSI_COLOR_CYAN    "\x1b[36m"
#define ANSI_COLOR_RESET   "\x1b[0m"

/* 全局日志管理器 */
static log_manager_t g_log_manager = {0};

/* 默认日志配置 */
static const log_config_t default_config = {
    .level = LOG_LEVEL_INFO,
    .output_mask = LOG_OUTPUT_CONSOLE | LOG_OUTPUT_FILE,
    .log_file = DTU_LOG_FILE_PATH,
    .max_file_size = 10 * 1024 * 1024,  /* 10MB */
    .max_backup_files = 5,
    .enable_color = true,
    .enable_timestamp = true,
    .enable_thread_id = true,
    .enable_function_name = true
};

/* 日志级别字符串映射 */
static const char* level_strings[] = {
    "DEBUG", "INFO", "WARN", "ERROR", "FATAL"
};

/* 日志级别颜色映射 */
static const char* level_colors[] = {
    ANSI_COLOR_CYAN,    /* DEBUG */
    ANSI_COLOR_BLUE,    /* INFO */
    ANSI_COLOR_YELLOW,  /* WARN */
    ANSI_COLOR_RED,     /* ERROR */
    ANSI_COLOR_MAGENTA  /* FATAL */
};

/* 内部函数声明 */
static void log_to_console(log_level_t level, const char* message);
static void log_to_file(log_level_t level, const char* message);
static void log_to_syslog(log_level_t level, const char* message);
static dtu_error_t create_log_directory(const char* log_file);
static dtu_error_t check_and_rotate_log(void);
static void format_timestamp(char* buffer, size_t size);

dtu_error_t dtu_log_init(const log_config_t* config)
{
    if (g_log_manager.initialized) {
        return DTU_OK;
    }

    /* 使用提供的配置或默认配置 */
    if (config) {
        g_log_manager.config = *config;
    } else {
        g_log_manager.config = default_config;
    }

    /* 初始化互斥锁 */
    if (pthread_mutex_init(&g_log_manager.mutex, NULL) != 0) {
        return DTU_ERROR;
    }

    /* 创建日志目录 */
    if (g_log_manager.config.output_mask & LOG_OUTPUT_FILE) {
        if (create_log_directory(g_log_manager.config.log_file) != DTU_OK) {
            pthread_mutex_destroy(&g_log_manager.mutex);
            return DTU_ERROR;
        }

        /* 打开日志文件 */
        g_log_manager.log_file_fp = fopen(g_log_manager.config.log_file, "a");
        if (!g_log_manager.log_file_fp) {
            pthread_mutex_destroy(&g_log_manager.mutex);
            return DTU_ERROR;
        }
    }

    /* 初始化系统日志 */
    if (g_log_manager.config.output_mask & LOG_OUTPUT_SYSLOG) {
        openlog("dtu", LOG_PID | LOG_CONS, LOG_DAEMON);
    }

    /* 初始化统计信息 */
    memset(&g_log_manager.stats, 0, sizeof(log_stats_t));

    g_log_manager.initialized = true;

    DTU_LOG_INFO("Log system initialized, level: %s, output: 0x%x", 
                 level_strings[g_log_manager.config.level], 
                 g_log_manager.config.output_mask);

    return DTU_OK;
}

void dtu_log_cleanup(void)
{
    if (!g_log_manager.initialized) {
        return;
    }

    pthread_mutex_lock(&g_log_manager.mutex);

    /* 关闭日志文件 */
    if (g_log_manager.log_file_fp) {
        fclose(g_log_manager.log_file_fp);
        g_log_manager.log_file_fp = NULL;
    }

    /* 关闭系统日志 */
    if (g_log_manager.config.output_mask & LOG_OUTPUT_SYSLOG) {
        closelog();
    }

    g_log_manager.initialized = false;

    pthread_mutex_unlock(&g_log_manager.mutex);
    pthread_mutex_destroy(&g_log_manager.mutex);
}

void dtu_log_write(log_level_t level, const char* file, int line, 
                   const char* func, const char* fmt, ...)
{
    if (!g_log_manager.initialized || level < g_log_manager.config.level) {
        return;
    }

    char message[4096];
    char timestamp[64];
    char thread_info[32];
    char location_info[256];
    
    /* 格式化时间戳 */
    if (g_log_manager.config.enable_timestamp) {
        format_timestamp(timestamp, sizeof(timestamp));
    } else {
        timestamp[0] = '\0';
    }

    /* 格式化线程信息 */
    if (g_log_manager.config.enable_thread_id) {
        snprintf(thread_info, sizeof(thread_info), "[%p] ", (void*)pthread_self());
    } else {
        thread_info[0] = '\0';
    }

    /* 格式化位置信息 */
    if (g_log_manager.config.enable_function_name) {
        const char* filename = strrchr(file, '/');
        filename = filename ? filename + 1 : file;
        snprintf(location_info, sizeof(location_info), "%s:%d %s() ", 
                filename, line, func);
    } else {
        location_info[0] = '\0';
    }

    /* 格式化用户消息 */
    va_list args;
    va_start(args, fmt);
    char user_message[2048];
    vsnprintf(user_message, sizeof(user_message), fmt, args);
    va_end(args);

    /* 组装完整消息 */
    snprintf(message, sizeof(message), "%s%s[%s] %s%s", 
             timestamp, thread_info, level_strings[level], 
             location_info, user_message);

    pthread_mutex_lock(&g_log_manager.mutex);

    /* 检查并轮转日志文件 */
    if (g_log_manager.config.output_mask & LOG_OUTPUT_FILE) {
        check_and_rotate_log();
    }

    /* 输出到各个目标 */
    if (g_log_manager.config.output_mask & LOG_OUTPUT_CONSOLE) {
        log_to_console(level, message);
    }

    if (g_log_manager.config.output_mask & LOG_OUTPUT_FILE) {
        log_to_file(level, message);
    }

    if (g_log_manager.config.output_mask & LOG_OUTPUT_SYSLOG) {
        log_to_syslog(level, user_message);
    }

    /* 更新统计信息 */
    switch (level) {
        case LOG_LEVEL_DEBUG: g_log_manager.stats.debug_count++; break;
        case LOG_LEVEL_INFO:  g_log_manager.stats.info_count++;  break;
        case LOG_LEVEL_WARN:  g_log_manager.stats.warn_count++;  break;
        case LOG_LEVEL_ERROR: g_log_manager.stats.error_count++; break;
        case LOG_LEVEL_FATAL: g_log_manager.stats.fatal_count++; break;
    }
    g_log_manager.stats.total_count++;
    g_log_manager.stats.total_size += strlen(message);

    pthread_mutex_unlock(&g_log_manager.mutex);
}

void dtu_log_hex(log_level_t level, const char* file, int line, 
                 const char* func, const void* data, size_t len, 
                 const char* fmt, ...)
{
    if (!g_log_manager.initialized || level < g_log_manager.config.level || !data || len == 0) {
        return;
    }

    /* 格式化用户消息 */
    char user_message[512];
    va_list args;
    va_start(args, fmt);
    vsnprintf(user_message, sizeof(user_message), fmt, args);
    va_end(args);

    /* 格式化十六进制数据 */
    char hex_buffer[2048];
    const uint8_t* bytes = (const uint8_t*)data;
    size_t hex_len = 0;
    
    for (size_t i = 0; i < len && hex_len < sizeof(hex_buffer) - 4; i++) {
        hex_len += snprintf(hex_buffer + hex_len, sizeof(hex_buffer) - hex_len, 
                           "%02X ", bytes[i]);
    }

    /* 组合消息 */
    char full_message[2560];
    snprintf(full_message, sizeof(full_message), "%s [%zu bytes]: %s", 
             user_message, len, hex_buffer);

    /* 调用普通日志函数 */
    dtu_log_write(level, file, line, func, "%s", full_message);
}

static void log_to_console(log_level_t level, const char* message)
{
    FILE* output = (level >= LOG_LEVEL_WARN) ? stderr : stdout;
    
    if (g_log_manager.config.enable_color && isatty(fileno(output))) {
        fprintf(output, "%s%s%s\n", level_colors[level], message, ANSI_COLOR_RESET);
    } else {
        fprintf(output, "%s\n", message);
    }
    
    fflush(output);
}

static void log_to_file(log_level_t level, const char* message)
{
    (void)level; /* 未使用的参数 */
    if (g_log_manager.log_file_fp) {
        fprintf(g_log_manager.log_file_fp, "%s\n", message);
        fflush(g_log_manager.log_file_fp);
    }
}

static void log_to_syslog(log_level_t level, const char* message)
{
    int syslog_level;
    switch (level) {
        case LOG_LEVEL_DEBUG: syslog_level = LOG_DEBUG; break;
        case LOG_LEVEL_INFO:  syslog_level = LOG_INFO;  break;
        case LOG_LEVEL_WARN:  syslog_level = LOG_WARNING; break;
        case LOG_LEVEL_ERROR: syslog_level = LOG_ERR;   break;
        case LOG_LEVEL_FATAL: syslog_level = LOG_CRIT;  break;
        default: syslog_level = LOG_INFO; break;
    }
    
    syslog(syslog_level, "%s", message);
}

static dtu_error_t create_log_directory(const char* log_file)
{
    char dir_path[256];
    DTU_STRNCPY(dir_path, log_file, sizeof(dir_path));
    
    char* last_slash = strrchr(dir_path, '/');
    if (last_slash) {
        *last_slash = '\0';
        
        struct stat st;
        if (stat(dir_path, &st) != 0) {
            if (mkdir(dir_path, 0755) != 0) {
                return DTU_ERROR;
            }
        }
    }
    
    return DTU_OK;
}

static dtu_error_t check_and_rotate_log(void)
{
    if (!g_log_manager.log_file_fp) {
        return DTU_OK;
    }

    /* 检查文件大小 */
    long file_size = ftell(g_log_manager.log_file_fp);
    if (file_size < (long)g_log_manager.config.max_file_size) {
        return DTU_OK;
    }

    /* 执行日志轮转 */
    return dtu_log_rotate();
}

static void format_timestamp(char* buffer, size_t size)
{
    time_t now = time(NULL);
    struct tm* tm_info = localtime(&now);
    
    strftime(buffer, size, "[%Y-%m-%d %H:%M:%S] ", tm_info);
}

dtu_error_t dtu_log_set_level(log_level_t level)
{
    if (!g_log_manager.initialized) {
        return DTU_ERROR;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    g_log_manager.config.level = level;
    pthread_mutex_unlock(&g_log_manager.mutex);

    return DTU_OK;
}

log_level_t dtu_log_get_level(void)
{
    if (!g_log_manager.initialized) {
        return LOG_LEVEL_INFO;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    log_level_t level = g_log_manager.config.level;
    pthread_mutex_unlock(&g_log_manager.mutex);

    return level;
}

dtu_error_t dtu_log_set_output(int output_mask)
{
    if (!g_log_manager.initialized) {
        return DTU_ERROR;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    g_log_manager.config.output_mask = output_mask;
    pthread_mutex_unlock(&g_log_manager.mutex);

    return DTU_OK;
}

int dtu_log_get_output(void)
{
    if (!g_log_manager.initialized) {
        return LOG_OUTPUT_CONSOLE;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    int output_mask = g_log_manager.config.output_mask;
    pthread_mutex_unlock(&g_log_manager.mutex);

    return output_mask;
}

void dtu_log_flush(void)
{
    if (!g_log_manager.initialized) {
        return;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    
    if (g_log_manager.log_file_fp) {
        fflush(g_log_manager.log_file_fp);
    }
    
    fflush(stdout);
    fflush(stderr);
    
    pthread_mutex_unlock(&g_log_manager.mutex);
}

dtu_error_t dtu_log_rotate(void)
{
    if (!g_log_manager.initialized || !g_log_manager.log_file_fp) {
        return DTU_ERROR;
    }

    pthread_mutex_lock(&g_log_manager.mutex);

    /* 关闭当前日志文件 */
    fclose(g_log_manager.log_file_fp);
    g_log_manager.log_file_fp = NULL;

    /* 轮转备份文件 */
    char old_file[300], new_file[300];
    
    for (int i = g_log_manager.config.max_backup_files - 1; i > 0; i--) {
        snprintf(old_file, sizeof(old_file), "%s.%d", g_log_manager.config.log_file, i - 1);
        snprintf(new_file, sizeof(new_file), "%s.%d", g_log_manager.config.log_file, i);
        rename(old_file, new_file);
    }

    /* 重命名当前日志文件 */
    snprintf(new_file, sizeof(new_file), "%s.0", g_log_manager.config.log_file);
    rename(g_log_manager.config.log_file, new_file);

    /* 创建新的日志文件 */
    g_log_manager.log_file_fp = fopen(g_log_manager.config.log_file, "w");
    
    pthread_mutex_unlock(&g_log_manager.mutex);

    return g_log_manager.log_file_fp ? DTU_OK : DTU_ERROR;
}

dtu_error_t dtu_log_get_stats(log_stats_t* stats)
{
    if (!stats) {
        return DTU_ERROR_INVALID_PARAM;
    }

    if (!g_log_manager.initialized) {
        memset(stats, 0, sizeof(log_stats_t));
        return DTU_OK;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    *stats = g_log_manager.stats;
    pthread_mutex_unlock(&g_log_manager.mutex);

    return DTU_OK;
}

void dtu_log_reset_stats(void)
{
    if (!g_log_manager.initialized) {
        return;
    }

    pthread_mutex_lock(&g_log_manager.mutex);
    memset(&g_log_manager.stats, 0, sizeof(log_stats_t));
    pthread_mutex_unlock(&g_log_manager.mutex);
}

const char* dtu_log_level_string(log_level_t level)
{
    if (level >= 0 && level < DTU_ARRAY_SIZE(level_strings)) {
        return level_strings[level];
    }
    return "UNKNOWN";
}

log_level_t dtu_log_level_from_string(const char* str)
{
    if (!str) {
        return LOG_LEVEL_INFO;
    }

    for (size_t i = 0; i < DTU_ARRAY_SIZE(level_strings); i++) {
        if (strcasecmp(str, level_strings[i]) == 0) {
            return (log_level_t)i;
        }
    }

    return LOG_LEVEL_INFO;
}

bool dtu_log_is_level_enabled(log_level_t level)
{
    if (!g_log_manager.initialized) {
        return false;
    }

    return level >= g_log_manager.config.level;
}
